package com.mszlu.blog.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mszlu.blog.dao.dos.Archives;
import com.mszlu.blog.dao.mapper.*;
import com.mszlu.blog.dao.pojo.Article;
import com.mszlu.blog.dao.pojo.ArticleBody;
import com.mszlu.blog.dao.pojo.ArticleTag;
import com.mszlu.blog.dao.pojo.SysUser;
import com.mszlu.blog.service.*;
import com.mszlu.blog.utils.UserThreadLocal;
import com.mszlu.blog.vo.*;
import com.mszlu.blog.vo.params.ArticleParam;
import com.mszlu.blog.vo.params.PageParams;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @Package: com.mszlu.blog.service.impl
 * @ClassName: ArticleServiceImpl
 * @Author: 陈威
 * @CreateTime: 2021/8/27 15:12
 * @Description:
 */
@SuppressWarnings("all")
@Service
@Transactional
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private TagService tagService;

    @Autowired
    ArticleTagMapper articleTagMapper;

    @Autowired
    ThreadService threadService;
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    CommentMapper commentMapper;

    @Autowired
    ArticleBodyMapper articleBodyMapper;

    @Autowired
    CategoryService categoryService;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    SysUserMapper userMapper;


    //首页文章列表
    @Override
    public Result listArticle(PageParams pageParams) {
        if (pageParams.getNickname() == null || pageParams.getNickname().length() <= 0) {
            Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
            IPage<Article> articleIPage = articleMapper.listArticle(
                    page,
                    pageParams.getCategoryId(),
                    pageParams.getTagId(),
                    pageParams.getYear(),
                    pageParams.getMonth(), pageParams.getNickname());

            List<Article> records = articleIPage.getRecords();
            List<ArticleVo> articleVoList = copyList(records, true, true);
            return Result.success(articleVoList);
        } else {
            List<Article> articles = articleMapper.listArticleByNickName(pageParams.getNickname());
            List<ArticleVo> articleVoList = copyList(articles, true, true);
            return Result.success(articleVoList);
        }

    }


    public Result listArticleAll(PageParams pageParams) {

        PageResult<ArticleVo> pageResult = null;
        try {
            Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
            IPage<Article> articleIPage = articleMapper.listArticleAll(
                    page, pageParams.getTitle(), pageParams.getAuthor());

            List<Article> records = articleIPage.getRecords();
            List<ArticleVo> articleVoList = copyList(records, true, true);
            pageResult = new PageResult<>();
            pageResult.setList(articleVoList);
            pageResult.setTotal(articleIPage.getTotal());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail(999, "系统错误");
        }
        return Result.success(pageResult);


    }


    /*//首页文章列表
    @Override
    public Result listArticles(PageParams pageParams) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
        //根据文章分类查询该分类下所属文章
        if (pageParams.getCategoryId()!=null){
            wrapper.eq(Article::getCategoryId,pageParams.getCategoryId());
        }

        //根据标签id查询所属文章
        List<Long> articleIdList=new ArrayList<>();
        if (pageParams.getTagId()!=null){
            LambdaQueryWrapper<ArticleTag> articleTagLambdaQueryWrapper=new LambdaQueryWrapper<>();
            articleTagLambdaQueryWrapper.eq(ArticleTag::getTagId,pageParams.getTagId());
            List<ArticleTag> articleTags = articleTagMapper.selectList(articleTagLambdaQueryWrapper);
            for (ArticleTag articleTag : articleTags) {
                articleIdList.add(articleTag.getArticleId());
            }

            if (articleIdList.size()>0){
                wrapper.in(Article::getId,articleIdList);
            }
        }

        //查询标签
        //是否置顶进行排序和按创建时间进行倒序排列
        wrapper.orderByAsc(Article::getCreateDate, Article::getWeight);

        //设置分页条件
        wrapper.last("limit "+(pageParams.getPage()*5-5)+","+pageParams.getPageSize());
        Page<Article> articlePage = articleMapper.selectPage(page, wrapper);
        //获取数据集合

        List<Article> records = articlePage.getRecords();

        List<ArticleVo> articleVoList = copyList(records, true, true);
        return Result.success(articleVoList);
    }
*/
    //最热文章
    @Override
    public Result hotArticle(int limit) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper();
        wrapper.orderByDesc(Article::getViewCounts);//根据阅读次数进行排序
        wrapper.select(Article::getId, Article::getTitle); //设置要获取的数据
        wrapper.last("limit " + limit); //取前limit个元素
        List<Article> articles = articleMapper.selectList(wrapper);

        return Result.success(articles);
    }

    //最新文章
    @Override
    public Result newArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);//设置条件 根据文章创建时间来进行查询
        queryWrapper.select(Article::getId, Article::getTitle);
        queryWrapper.last("limit " + limit);
        List<Article> articles = articleMapper.selectList(queryWrapper);
        return Result.success(articles);
    }

    //文章归档
    @Override
    public Result listArchives() {
        List<Archives> list = articleMapper.listArchives();
        return Result.success(list);
    }


    //将article里的数据向ArticleVo中复制 多条复制   方法重载 主要用于首页文章列表
    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor) {
        List<ArticleVo> list = new ArrayList<>();
        for (Article record : records) {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set(record.getId() + "viewCount", JSON.toJSONString(record.getViewCounts()));
            operations.set(record.getId() + "commentCounts", JSON.toJSONString(record.getCommentCounts()));
            record.setViewCounts(Integer.valueOf(operations.get(record.getId() + "viewCount")));
            record.setCommentCounts(Integer.valueOf(operations.get(record.getId() + "commentCounts")));
            list.add(copy(record, isTag, isAuthor, false, false));
        }
        return list;
    }

    //方法重载 主要用于获取文章详细内容
    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor, boolean isBody, boolean isCategory) {
        List<ArticleVo> list = new ArrayList<>();
        for (Article record : records) {
            list.add(copy(record, isTag, isAuthor, isBody, isCategory));
        }
        return list;
    }


    //将article里的数据向ArticleVo中复制 单条复制
    private ArticleVo copy(Article article, boolean isTag, boolean isAuthor, boolean isBody, boolean isCategory) {
        ArticleVo articleVo = new ArticleVo();
        articleVo.setId(String.valueOf(article.getId()));
        //利用BeanUtils将Article与ArticleVo里面相同的属性copy到ArticleVo中
        BeanUtils.copyProperties(article, articleVo);
        //由于两者的CreateDate类型不同 所以需要手动注入
        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));

        if (isTag) {
            Long articleId = article.getId();
            //获取该id对应的文章
            articleVo.setTags(tagService.findTagsByArticleId(articleId));
        }
        if (isAuthor) {
            Long authorId = article.getAuthorId();
            UserVo userById = sysUserService.findUserById(authorId);
            //设置作者
            articleVo.setAuthor(userById.getNickname());
            articleVo.setUid(userById.getId());
        }
        //查询body信息
        if (isBody) {
            Long bodyId = article.getBodyId();
            articleVo.setBody(findArticleBodyById(bodyId));
        }
        //查询分类信息
        if (isCategory) {
            Long categoryId = article.getCategoryId();
            CategoryVo categoryById = categoryService.findCategoryById(categoryId);
            articleVo.setCategorys(categoryById);
        }
        return articleVo;
    }

    int count = 0; //对应的文章计数器

    //查看文章详细信息
    //根据id查询文章信息  根据body_id和category_id做关联查询
    @Override
    public Result findArticleById(Long id) {
        count++;
        Article article = articleMapper.selectByIdOne(id);
        //调用方法为参数赋值
        ArticleVo articleVo = copy(article, true, true, true, true);

        //阅读量增加 更新redis中相应文章的阅读量
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        //查看文章详情时获取文章相应阅读量
        String reviewCountsadnum = operations.get(article.getId() + "viewCount");
        //查看文章详情时获取文章相应评论量
        String commentCounts = operations.get(article.getId() + "commentCounts");

        operations.increment(id + "viewCount");
        //operations.increment(id+"commentCounts");
        articleVo.setViewCounts(Integer.valueOf(reviewCountsadnum));
        articleVo.setCommentCounts(Integer.valueOf(commentCounts));

     /*   //更新对应文章的（阅读量，评论量）
        RedisDataPersistenceJob redisDataPersistenceJob=new RedisDataPersistenceJob();
        redisDataPersistenceJob.doWork(article);*/

        //在redis中存入评论和阅读总数量
        //查看完文章了，新增阅读数，有没有问题呢？
        //查看完文章之后，本应该直接返回数据了，这时候做了一个更新操作，更新时加写锁，阻塞其他的读操作，性能就会比较低
        // 更新 增加了此次接口的 耗时 如果一旦更新出问题，不能影响 查看文章的操作
        //线程池  可以把更新操作 扔到线程池中去执行，和主线程就不相关了
        if (count % 5 == 0) {
            threadService.updateArticleViewCount(articleMapper, article);
        }
        return Result.success(articleVo);
    }


    //根据id查询body信息
    private ArticleBodyVo findArticleBodyById(Long bodyId) {
        //得到数据
        ArticleBody articleBody = articleBodyMapper.selectById(bodyId);
        ArticleBodyVo articleBodyVo = new ArticleBodyVo();
        //将数据转换为需要的数据结构
        articleBodyVo.setContent(articleBody.getContent());
        return articleBodyVo;

    }

    //发布文章或修改文章
    @Override
    public Result publish(ArticleParam articleParam) {
        SysUser sysUser = UserThreadLocal.get();
        Article article = new Article();
      /*  SensitiveFilter filter = SensitiveFilter.DEFAULT;
        //敏感词过滤
        if (articleParam != null) {
            if (articleParam.getTitle() != null) {
                String filter1 = filter.filter(articleParam.getTitle(), '*');
                if (filter1 != articleParam.getTitle()) {
                    articleParam.setIsViolations(true);
                    articleParam.setIsViolationStr(articleParam.getTitle() + ",");
                    articleParam.setTitle(filter1);
                }
                String filter2 = filter.filter(articleParam.getSummary(), '*');
                if (filter1 != articleParam.getSummary()) {
                    articleParam.setIsViolations(true);
                    articleParam.setIsViolationStr(articleParam.getIsViolationStr() + articleParam.getSummary() + ",");
                    articleParam.setSummary(filter2);
                }
                String filter3 = filter.filter(articleParam.getBody().getContent(), '*');
                if (filter1 != articleParam.getTitle()) {
                    articleParam.setIsViolations(true);
                    articleParam.setIsViolationStr(articleParam.getIsViolationStr() + articleParam.getBody().getContent() + ",");
                    articleParam.getBody().setContent(filter3);
                }
                String filter4 = filter.filter(articleParam.getBody().getContentHtml(), '*');
                if (filter1 != articleParam.getSummary()) {
                    articleParam.setIsViolations(true);
                    articleParam.setIsViolationStr(articleParam.getIsViolationStr() + articleParam.getBody().getContentHtml() + ",");
                    articleParam.setTitle(filter4);
                }
            }
        }*/


        if ("insertArticle".equals(articleParam.getType())) {

        /*
            1.发布文章，构建Article对象
            2。作者id 当前的登录用户  将当前接口加入登录拦截器拦截路径
            3.
         *
         **/
/*            if (articleParam.getIsViolations()){
                article.setIsViolations(YES_NO.YES.getValue());
            }else {
                article.setIsViolations(YES_NO.NO.getValue());
            }*/
            article.setAuthorId(sysUser.getId());
            article.setWeight(Article.Article_Common);
            article.setViewCounts(0);
            article.setTitle(articleParam.getTitle());
            article.setCategoryId(Long.parseLong(articleParam.getCategory().getId()));
            article.setSummary(articleParam.getSummary());
            article.setCommentCounts(0);
            article.setCreateDate(System.currentTimeMillis());
            //插入之后会生成一个文章id
            articleMapper.insert(article);
            List<TagVo> tags = articleParam.getTags();
            if (tags != null) {
                for (TagVo tag : tags) {
                    Long articleId = article.getId();
                    ArticleTag articleTag = new ArticleTag();
                    articleTag.setTagId(Long.parseLong(tag.getId()));
                    articleTag.setArticleId(articleId);
                    articleTagMapper.insert(articleTag);
                }

                //body 文章内容
                ArticleBody articleBody = new ArticleBody();
                articleBody.setArticleId(article.getId());
                articleBody.setContent(articleParam.getBody().getContent());
                articleBody.setContentHtml(articleParam.getBody().getContentHtml());
                articleBodyMapper.insert(articleBody);
                article.setBodyId(articleBody.getId());

                articleMapper.updateById(article);
            }
            ArticleVo articleVo = new ArticleVo();
            articleVo.setId(String.valueOf(article.getId()));
        } else if ("updateArticle".equals(articleParam.getType())) {
            article.setId(articleParam.getId());
            article.setAuthorId(sysUser.getId());
            article.setWeight(Article.Article_Common);
            article.setViewCounts(0);
            article.setTitle(articleParam.getTitle());
            article.setCategoryId(Long.parseLong(articleParam.getCategory().getId()));
            article.setSummary(articleParam.getSummary());
            article.setCommentCounts(0);
            article.setCreateDate(System.currentTimeMillis());


            articleMapper.updateArticle(article);

            Long articleId = article.getId();
            List<TagVo> tags = articleParam.getTags();

            if (tags != null) {
                //更改标签前 删掉旧标签
                LambdaUpdateWrapper<ArticleTag> updateWrapper = new LambdaUpdateWrapper<>();
                articleTagMapper.delete(updateWrapper);
                for (TagVo tag : tags) {
                    ArticleTag articleTag = new ArticleTag();
                    articleTag.setTagId(Long.parseLong(tag.getId()));
                    articleTag.setArticleId(articleId);
                    updateWrapper.eq(ArticleTag::getArticleId, articleId);
                    articleTagMapper.insert(articleTag);

                }

                //body 文章内容
                ArticleBody articleBody = new ArticleBody();
                articleBody.setArticleId(article.getId());
                articleBody.setContent(articleParam.getBody().getContent());
                articleBody.setContentHtml(articleParam.getBody().getContentHtml());
                LambdaUpdateWrapper<ArticleBody> updateWrapperBody = new LambdaUpdateWrapper<>();
                updateWrapperBody.eq(ArticleBody::getArticleId, articleId);
                articleBodyMapper.update(articleBody, updateWrapperBody);
            }
        } else {
            return Result.fail(999, "保存失败");
        }

        return Result.success("保存成功");
    }

    //删除文章
    @Override
    public Result deleteArticle(Long id) {

        try {
            articleMapper.deleteById(id);
            LambdaUpdateWrapper<ArticleBody> updateWrapperBody = new LambdaUpdateWrapper<>();
            updateWrapperBody.eq(ArticleBody::getArticleId, id);
            articleBodyMapper.delete(updateWrapperBody);
            LambdaUpdateWrapper<ArticleTag> updateWrapperTag = new LambdaUpdateWrapper<>();
            updateWrapperTag.eq(ArticleTag::getArticleId, id);
            articleTagMapper.delete(updateWrapperTag);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail(999, "删除失败");
        }

        return Result.success("删除成功");
    }
}